/*
 * Copyright (c)  2020,  DataPipeline
 * All rights reserved.
 *
 * Id:DefaultMapperBuilder.java   2020-07-18 22:45 wanglijun
 */
package cn.datacare.orm.mapper;

import cn.datacare.orm.conversion.SqlIdNameConversion;
import cn.datacare.orm.manager.impl.SQLManager;
import cn.datacare.orm.mapper.proxy.MapperJavaProxy;
import cn.datacare.orm.mapper.proxy.MapperJavaSpiderProxy;
import cn.datacare.orm.util.BeanUtils;

import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * Title: DefaultMapperBuilder
 * </p>
 * <p>
 * Description:  默认Java代理实现.
 * </p>
 * <p>
 * Copyright: Copyright (c) 2020
 * </p>
 * <p>
 * Company/Department: DataPipeline
 * </p>
 *
 * @author wanglijun
 * @version 1.0
 * @since 2020-07-18 22:45
 */
public class DefaultMapperBuilder implements MapperBuilder {


    /**
     * The cache.
     */
    protected Map<Class<?>, Object> cache = new ConcurrentHashMap<>();

    /**
     * The sql manager.
     */
    protected SQLManager sqlManager;

    protected ClassLoader entityClassLoader;


    /**
     * The Constructor.
     *
     * @param sqlManager the sql manager
     */
    public DefaultMapperBuilder(SQLManager sqlManager) {
        super();
        this.sqlManager = sqlManager;
        this.entityClassLoader = sqlManager.getEntityLoader();
    }

    /**
     * The Constructor.,不推荐使用，使用SQLManager.setEntityLoader()
     *
     * @param sqlManager  the sql manager
     * @param classLoader specified class loader for loading mapped entities
     */
    @Deprecated
    public DefaultMapperBuilder(SQLManager sqlManager, ClassLoader classLoader) {
        this(sqlManager);
        this.entityClassLoader = classLoader;
    }

    /**
     * (non-Javadoc)
     *
     * @see org.beetl.sql.ext.dao2.MapperBuilder#getMapper(java.lang.Class)
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getMapper(Class<T> mapperInterface) {
        if (cache.containsKey(mapperInterface)) {
            return (T) cache.get(mapperInterface);
        } else {
            T instance = this.buildInstance(mapperInterface);
            cache.put(mapperInterface, instance);
            return instance;
        }
    }

    /**
     * Builds the instance.
     *
     * @param <T>             the generic type
     * @param mapperInterface the dao2 interface
     * @return the t
     */
    @SuppressWarnings("unchecked")
    public <T> T buildInstance(Class<T> mapperInterface) {
        ClassLoader loader = null == entityClassLoader ? Thread.currentThread().getContextClassLoader() : entityClassLoader;
        //当没有指定ClassLoader的情况下使用ContextLoader，适合大多数框架
        if (BeanUtils.queryLambdasSupport) {
            return (T) Proxy.newProxyInstance(loader == null ? this.getClass().getClassLoader() : loader, new Class<?>[]{mapperInterface},
                    new MapperJavaSpiderProxy(this, sqlManager, mapperInterface));
        } else {
            return (T) Proxy.newProxyInstance(loader == null ? this.getClass().getClassLoader() : loader, new Class<?>[]{mapperInterface},
                    new MapperJavaProxy(this, sqlManager, mapperInterface));
        }

    }

    public SqlIdNameConversion getIdGen() {
        return sqlManager.getSQLIdNameConversion();
    }
}
